package com.common.util;

import com.google.common.collect.Lists;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;

public class ReflectUtil<T> {
	/**
	 * 复制两个相同类型对象的属性，从源对象 复制到 目标对象
	 * @param src 源对象
	 * @param tar 目标对象	 
	 * @param isCopyNull true包括空值
	 * @param ignoreField 不需要复制的属性列表
	 * @throws RuntimeException
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static void copyProperties(Object src, Object tar,boolean isCopyNull, String... ignoreField) throws RuntimeException {
		if (src == null || tar == null || src.getClass() != tar.getClass()) {
			return;
		}
		Set ignoreSet = new HashSet();
		if (ignoreField != null) {
			Collections.addAll(ignoreSet, ignoreField);
		}
		Collections.addAll(ignoreSet, "serialVersionUID");
		Class srcClazz = src.getClass();
		Field[] srcFields = srcClazz.getDeclaredFields();

		Class tarClazz = src.getClass();
		Field[] tarFields = tarClazz.getDeclaredFields();
		try {
			// 遍历源对象属性
			for (Field f : srcFields) {
//				String type = f.getType().getName();
				// 设置通过反射访问该成员变量时取消访问权限检查
				f.setAccessible(true);
				// 遍历目标对象属性
				for (Field tarField : tarFields) {
					tarField.setAccessible(true);
					String tField = tarField.getName();
					// 忽略不复制的属性，属性名一致才复制
					if (!ignoreSet.contains(tField) && f.getName().equals(tField)) {
						if(isCopyNull){
							tarField.set(tar, f.get(src));
						}else if(f.get(src)!=null){
							tarField.set(tar, f.get(src));
						}
					}
				}
			}
		} catch (IllegalArgumentException | IllegalAccessException e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 获取指定字段的值
	 * @param entity
	 * @param fieldName
	 * @return
	 */
	public static String getValueFromObject(Object entity,String fieldName){
		for (Class<?> superClass = entity.getClass(); superClass != Object.class; superClass = superClass
                .getSuperclass()) {
            try {
                Field f = superClass.getDeclaredField(fieldName);
                f.setAccessible(true);
				return (String) f.get(entity);
            } catch (RuntimeException | IllegalAccessException | NoSuchFieldException e) {
            }
        }
		return null;
	}
	
	public static Field getFieldFromObject(Object entity,String fieldName){
		for (Class<?> superClass = entity.getClass(); superClass != Object.class; superClass = superClass
                .getSuperclass()) {
            try {
            	return superClass.getDeclaredField(fieldName);
            } catch (RuntimeException | NoSuchFieldException e) {
            }
        }
		return null;
	}

	public  List<T> mapToObjects(List<Map<String, Object>> mapList, T beanClass) throws Exception {
		List<T> beanClassS= Lists.newArrayList();
		mapList.forEach(map -> {
			try {
				T object = (T)ReflectUtil.mapToObject(map, beanClass.getClass());
				beanClassS.add(object);
			} catch (Exception e) {
				e.printStackTrace();
			}
		});
		return beanClassS;
	}

	public static Object mapToObject(Map<String, Object> map, Class<?> beanClass) throws Exception {
		if (map == null)
			return null;
		Object obj = beanClass.newInstance();
		Field[] fields = obj.getClass().getDeclaredFields();
		for (Field field : fields) {
			int mod = field.getModifiers();
			if(Modifier.isStatic(mod) || Modifier.isFinal(mod)){
				continue;
			}
			field.setAccessible(true);
			field.set(obj, map.get(field.getName()));
		}
		return obj;
	}

	public static Map<String, Object> objectToMap(Object obj) throws Exception {
		if(obj == null){
			return null;
		}
		Map<String, Object> map = new HashMap<String, Object>();
		Field[] declaredFields = obj.getClass().getDeclaredFields();
		for (Field field : declaredFields) {
			field.setAccessible(true);
			map.put(field.getName(), field.get(obj));
		}
		return map;
	}

	public static Object mapToObjectIgnoreCase(Map<String, Object> map, Class<?> beanClass) throws Exception {
		if (map == null)
			return null;
		Object obj = beanClass.newInstance();
		Field[] fields = obj.getClass().getDeclaredFields();
		for (Field field : fields) {
			int mod = field.getModifiers();
			if(Modifier.isStatic(mod) || Modifier.isFinal(mod)){
				continue;
			}
			field.setAccessible(true);
			if("totalfee".equals(field.getName().toLowerCase())){
				field.set(obj, Integer.parseInt(map.get(field.getName().toLowerCase()).toString()));
			}else if("refundfee".equals(field.getName().toLowerCase())){
				field.set(obj, Integer.parseInt(map.get(field.getName().toLowerCase()).toString()));
			}else{
				field.set(obj, map.get(field.getName().toLowerCase()));
			}
		}
		return obj;
	}
}
